from flask import Flask, render_template, redirect, url_for, request, flash, session
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timedelta
import bcrypt
import os
from functools import wraps

# 初始化Flask应用
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///tasks.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# 初始化数据库
db = SQLAlchemy(app)

# 定义用户模型
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    tasks = db.relationship('Task', backref='user', lazy=True)
    categories = db.relationship('Category', backref='user', lazy=True)
    notifications = db.relationship('Notification', backref='user', lazy=True)

    def set_password(self, password):
        self.password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

    def check_password(self, password):
        return bcrypt.checkpw(password.encode('utf-8'), self.password_hash.encode('utf-8'))

# 定义分类模型
class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    color = db.Column(db.String(20), default='#007bff')
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    tasks = db.relationship('Task', backref='category', lazy=True)

# 定义任务模型
class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    due_date = db.Column(db.DateTime)
    priority = db.Column(db.String(20), default='medium')  # high, medium, low
    status = db.Column(db.String(20), default='todo')  # todo, in_progress, completed, archived
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    comments = db.relationship('Comment', backref='task', lazy=True)

# 定义评论模型
class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    task_id = db.Column(db.Integer, db.ForeignKey('task.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

# 定义通知模型
class Notification(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text, nullable=False)
    is_read = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

# 登录装饰器
def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session:
            flash('请先登录', 'danger')
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated_function

# 初始化数据库和创建默认用户
def init_db():
    with app.app_context():
        db.create_all()
        
        # 检查是否已有用户
        if not User.query.first():
            # 创建管理员用户
            admin = User(username='admin', email='admin@example.com')
            admin.set_password('admin123')
            db.session.add(admin)
            db.session.commit()
            
            # 创建默认分类
            default_categories = [
                {'name': '工作', 'color': '#007bff'},
                {'name': '学习', 'color': '#28a745'},
                {'name': '生活', 'color': '#dc3545'},
                {'name': '健康', 'color': '#ffc107'},
                {'name': '其他', 'color': '#6c757d'}
            ]
            
            for cat in default_categories:
                category = Category(name=cat['name'], color=cat['color'], user_id=admin.id)
                db.session.add(category)
            db.session.commit()
            
            # 创建示例任务
            categories = Category.query.filter_by(user_id=admin.id).all()
            example_tasks = [
                {
                    'title': '完成项目文档',
                    'description': '撰写项目的详细说明文档，包括功能介绍、使用方法和技术实现。',
                    'due_date': datetime.utcnow() + timedelta(days=3),
                    'priority': 'high',
                    'status': 'todo',
                    'category_id': categories[0].id
                },
                {
                    'title': '学习新的Python库',
                    'description': '研究Flask-RESTful库的使用方法，为项目添加API功能。',
                    'due_date': datetime.utcnow() + timedelta(days=7),
                    'priority': 'medium',
                    'status': 'todo',
                    'category_id': categories[1].id
                },
                {
                    'title': '完成任务管理系统的首页设计',
                    'description': '设计和实现用户友好的仪表盘界面，展示任务统计和进度。',
                    'due_date': datetime.utcnow() + timedelta(days=2),
                    'priority': 'high',
                    'status': 'in_progress',
                    'category_id': categories[0].id
                }
            ]
            
            for task_data in example_tasks:
                task = Task(
                    title=task_data['title'],
                    description=task_data['description'],
                    due_date=task_data['due_date'],
                    priority=task_data['priority'],
                    status=task_data['status'],
                    user_id=admin.id,
                    category_id=task_data['category_id']
                )
                db.session.add(task)
            db.session.commit()

# 首页/仪表盘
@app.route('/')
@login_required
def dashboard():
    user_id = session['user_id']
    user = User.query.get_or_404(user_id)
    
    # 获取任务统计数据
    total_tasks = Task.query.filter_by(user_id=user_id).count()
    todo_tasks = Task.query.filter_by(user_id=user_id, status='todo').count()
    in_progress_tasks = Task.query.filter_by(user_id=user_id, status='in_progress').count()
    completed_tasks = Task.query.filter_by(user_id=user_id, status='completed').count()
    
    # 获取最近的5个任务
    recent_tasks = Task.query.filter_by(user_id=user_id)
        .order_by(Task.created_at.desc())
        .limit(5)
        .all()
    
    # 获取截止日期临近的任务（3天内）
    upcoming_deadlines = Task.query.filter(
        Task.user_id == user_id,
        Task.status != 'completed',
        Task.status != 'archived',
        Task.due_date <= datetime.utcnow() + timedelta(days=3),
        Task.due_date >= datetime.utcnow()
    ).order_by(Task.due_date.asc()).all()
    
    # 获取未读通知
    unread_notifications = Notification.query.filter_by(user_id=user_id, is_read=False).count()
    
    return render_template('dashboard.html', 
                           user=user,
                           total_tasks=total_tasks,
                           todo_tasks=todo_tasks,
                           in_progress_tasks=in_progress_tasks,
                           completed_tasks=completed_tasks,
                           recent_tasks=recent_tasks,
                           upcoming_deadlines=upcoming_deadlines,
                           unread_notifications=unread_notifications)

# 注册页面
@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        email = request.form['email']
        password = request.form['password']
        confirm_password = request.form['confirm_password']
        
        # 验证表单数据
        if not username or not email or not password:
            flash('请填写所有必填字段', 'danger')
            return redirect(url_for('register'))
        
        if password != confirm_password:
            flash('两次输入的密码不一致', 'danger')
            return redirect(url_for('register'))
        
        # 检查用户名和邮箱是否已存在
        if User.query.filter_by(username=username).first():
            flash('用户名已存在', 'danger')
            return redirect(url_for('register'))
        
        if User.query.filter_by(email=email).first():
            flash('邮箱已被注册', 'danger')
            return redirect(url_for('register'))
        
        # 创建新用户
        new_user = User(username=username, email=email)
        new_user.set_password(password)
        
        try:
            db.session.add(new_user)
            db.session.commit()
            
            # 创建默认分类
            default_categories = [
                {'name': '工作', 'color': '#007bff'},
                {'name': '学习', 'color': '#28a745'},
                {'name': '生活', 'color': '#dc3545'},
                {'name': '健康', 'color': '#ffc107'},
                {'name': '其他', 'color': '#6c757d'}
            ]
            
            for cat in default_categories:
                category = Category(name=cat['name'], color=cat['color'], user_id=new_user.id)
                db.session.add(category)
            db.session.commit()
            
            flash('注册成功，请登录', 'success')
            return redirect(url_for('login'))
        except:
            db.session.rollback()
            flash('注册失败，请稍后再试', 'danger')
            return redirect(url_for('register'))
    
    return render_template('register.html')

# 登录页面
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        # 验证表单数据
        if not username or not password:
            flash('请填写所有必填字段', 'danger')
            return redirect(url_for('login'))
        
        # 查找用户
        user = User.query.filter_by(username=username).first()
        
        # 验证用户和密码
        if user and user.check_password(password):
            session['user_id'] = user.id
            session['username'] = user.username
            flash('登录成功', 'success')
            return redirect(url_for('dashboard'))
        else:
            flash('用户名或密码错误', 'danger')
            return redirect(url_for('login'))
    
    return render_template('login.html')

# 登出功能
@app.route('/logout')
@login_required
def logout():
    session.clear()
    flash('已成功登出', 'success')
    return redirect(url_for('login'))

# 任务列表
@app.route('/tasks')
@login_required
def task_list():
    user_id = session['user_id']
    status = request.args.get('status', 'all')
    priority = request.args.get('priority', 'all')
    category = request.args.get('category', 'all')
    search = request.args.get('search', '')
    
    # 构建查询
    query = Task.query.filter_by(user_id=user_id)
    
    # 按状态筛选
    if status != 'all':
        query = query.filter_by(status=status)
    
    # 按优先级筛选
    if priority != 'all':
        query = query.filter_by(priority=priority)
    
    # 按分类筛选
    if category != 'all' and category.isdigit():
        query = query.filter_by(category_id=int(category))
    
    # 搜索任务
    if search:
        search = f'%{search}%'
        query = query.filter(Task.title.like(search) | Task.description.like(search))
    
    # 获取所有任务并按更新时间排序
    tasks = query.order_by(Task.updated_at.desc()).all()
    
    # 获取所有分类
    categories = Category.query.filter_by(user_id=user_id).all()
    
    return render_template('task_list.html', 
                           tasks=tasks,
                           categories=categories,
                           current_status=status,
                           current_priority=priority,
                           current_category=category,
                           search_term=search)

# 添加任务
@app.route('/tasks/add', methods=['GET', 'POST'])
@login_required
def add_task():
    user_id = session['user_id']
    categories = Category.query.filter_by(user_id=user_id).all()
    
    if request.method == 'POST':
        title = request.form['title']
        description = request.form['description']
        due_date_str = request.form['due_date']
        priority = request.form['priority']
        status = request.form['status']
        category_id = request.form['category_id']
        
        # 验证表单数据
        if not title:
            flash('任务标题不能为空', 'danger')
            return redirect(url_for('add_task'))
        
        # 处理截止日期
        due_date = None
        if due_date_str:
            try:
                due_date = datetime.strptime(due_date_str, '%Y-%m-%dT%H:%M')
            except ValueError:
                flash('日期格式不正确', 'danger')
                return redirect(url_for('add_task'))
        
        # 处理分类
        category_id = int(category_id) if category_id else None
        
        # 创建新任务
        new_task = Task(
            title=title,
            description=description,
            due_date=due_date,
            priority=priority,
            status=status,
            user_id=user_id,
            category_id=category_id
        )
        
        try:
            db.session.add(new_task)
            db.session.commit()
            flash('任务创建成功', 'success')
            return redirect(url_for('task_list'))
        except:
            db.session.rollback()
            flash('任务创建失败，请稍后再试', 'danger')
            return redirect(url_for('add_task'))
    
    return render_template('add_task.html', categories=categories)

# 查看任务详情
@app.route('/tasks/<int:task_id>')
@login_required
def view_task(task_id):
    user_id = session['user_id']
    task = Task.query.filter_by(id=task_id, user_id=user_id).first_or_404()
    comments = Comment.query.filter_by(task_id=task_id).order_by(Comment.created_at.desc()).all()
    
    return render_template('view_task.html', task=task, comments=comments)

# 编辑任务
@app.route('/tasks/<int:task_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_task(task_id):
    user_id = session['user_id']
    task = Task.query.filter_by(id=task_id, user_id=user_id).first_or_404()
    categories = Category.query.filter_by(user_id=user_id).all()
    
    if request.method == 'POST':
        title = request.form['title']
        description = request.form['description']
        due_date_str = request.form['due_date']
        priority = request.form['priority']
        status = request.form['status']
        category_id = request.form['category_id']
        
        # 验证表单数据
        if not title:
            flash('任务标题不能为空', 'danger')
            return redirect(url_for('edit_task', task_id=task_id))
        
        # 处理截止日期
        due_date = None
        if due_date_str:
            try:
                due_date = datetime.strptime(due_date_str, '%Y-%m-%dT%H:%M')
            except ValueError:
                flash('日期格式不正确', 'danger')
                return redirect(url_for('edit_task', task_id=task_id))
        
        # 处理分类
        category_id = int(category_id) if category_id else None
        
        # 更新任务
        task.title = title
        task.description = description
        task.due_date = due_date
        task.priority = priority
        task.status = status
        task.category_id = category_id
        task.updated_at = datetime.utcnow()
        
        try:
            db.session.commit()
            flash('任务更新成功', 'success')
            return redirect(url_for('view_task', task_id=task_id))
        except:
            db.session.rollback()
            flash('任务更新失败，请稍后再试', 'danger')
            return redirect(url_for('edit_task', task_id=task_id))
    
    # 格式化日期时间为HTML5 datetime-local格式
    due_date_formatted = task.due_date.strftime('%Y-%m-%dT%H:%M') if task.due_date else ''
    
    return render_template('edit_task.html', task=task, categories=categories, due_date_formatted=due_date_formatted)

# 删除任务
@app.route('/tasks/<int:task_id>/delete', methods=['POST'])
@login_required
def delete_task(task_id):
    user_id = session['user_id']
    task = Task.query.filter_by(id=task_id, user_id=user_id).first_or_404()
    
    try:
        # 删除相关评论
        Comment.query.filter_by(task_id=task_id).delete()
        # 删除任务
        db.session.delete(task)
        db.session.commit()
        flash('任务已删除', 'success')
    except:
        db.session.rollback()
        flash('任务删除失败，请稍后再试', 'danger')
    
    return redirect(url_for('task_list'))

# 添加评论
@app.route('/tasks/<int:task_id>/comment', methods=['POST'])
@login_required
def add_comment(task_id):
    user_id = session['user_id']
    task = Task.query.filter_by(id=task_id, user_id=user_id).first_or_404()
    content = request.form['content']
    
    if not content:
        flash('评论内容不能为空', 'danger')
        return redirect(url_for('view_task', task_id=task_id))
    
    new_comment = Comment(content=content, task_id=task_id, user_id=user_id)
    
    try:
        db.session.add(new_comment)
        db.session.commit()
        flash('评论添加成功', 'success')
    except:
        db.session.rollback()
        flash('评论添加失败，请稍后再试', 'danger')
    
    return redirect(url_for('view_task', task_id=task_id))

# 分类管理
@app.route('/categories')
@login_required
def category_list():
    user_id = session['user_id']
    categories = Category.query.filter_by(user_id=user_id).all()
    return render_template('category_list.html', categories=categories)

# 添加分类
@app.route('/categories/add', methods=['GET', 'POST'])
@login_required
def add_category():
    user_id = session['user_id']
    
    if request.method == 'POST':
        name = request.form['name']
        color = request.form['color']
        
        if not name:
            flash('分类名称不能为空', 'danger')
            return redirect(url_for('add_category'))
        
        if Category.query.filter_by(name=name, user_id=user_id).first():
            flash('分类名称已存在', 'danger')
            return redirect(url_for('add_category'))
        
        new_category = Category(name=name, color=color, user_id=user_id)
        
        try:
            db.session.add(new_category)
            db.session.commit()
            flash('分类创建成功', 'success')
            return redirect(url_for('category_list'))
        except:
            db.session.rollback()
            flash('分类创建失败，请稍后再试', 'danger')
            return redirect(url_for('add_category'))
    
    return render_template('add_category.html')

# 编辑分类
@app.route('/categories/<int:category_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_category(category_id):
    user_id = session['user_id']
    category = Category.query.filter_by(id=category_id, user_id=user_id).first_or_404()
    
    if request.method == 'POST':
        name = request.form['name']
        color = request.form['color']
        
        if not name:
            flash('分类名称不能为空', 'danger')
            return redirect(url_for('edit_category', category_id=category_id))
        
        # 检查是否有同名分类
        existing_category = Category.query.filter_by(name=name, user_id=user_id).first()
        if existing_category and existing_category.id != category_id:
            flash('分类名称已存在', 'danger')
            return redirect(url_for('edit_category', category_id=category_id))
        
        category.name = name
        category.color = color
        
        try:
            db.session.commit()
            flash('分类更新成功', 'success')
            return redirect(url_for('category_list'))
        except:
            db.session.rollback()
            flash('分类更新失败，请稍后再试', 'danger')
            return redirect(url_for('edit_category', category_id=category_id))
    
    return render_template('edit_category.html', category=category)

# 删除分类
@app.route('/categories/<int:category_id>/delete', methods=['POST'])
@login_required
def delete_category(category_id):
    user_id = session['user_id']
    category = Category.query.filter_by(id=category_id, user_id=user_id).first_or_404()
    
    # 检查是否有任务使用该分类
    if Task.query.filter_by(category_id=category_id, user_id=user_id).first():
        flash('该分类下有任务，无法删除', 'danger')
        return redirect(url_for('category_list'))
    
    try:
        db.session.delete(category)
        db.session.commit()
        flash('分类已删除', 'success')
    except:
        db.session.rollback()
        flash('分类删除失败，请稍后再试', 'danger')
    
    return redirect(url_for('category_list'))

# 个人设置
@app.route('/settings', methods=['GET', 'POST'])
@login_required
def settings():
    user_id = session['user_id']
    user = User.query.get_or_404(user_id)
    
    if request.method == 'POST':
        # 更新用户信息
        username = request.form['username']
        email = request.form['email']
        
        # 验证表单数据
        if not username or not email:
            flash('请填写所有必填字段', 'danger')
            return redirect(url_for('settings'))
        
        # 检查用户名和邮箱是否已存在（排除当前用户）
        existing_user = User.query.filter_by(username=username).first()
        if existing_user and existing_user.id != user_id:
            flash('用户名已存在', 'danger')
            return redirect(url_for('settings'))
        
        existing_email = User.query.filter_by(email=email).first()
        if existing_email and existing_email.id != user_id:
            flash('邮箱已被注册', 'danger')
            return redirect(url_for('settings'))
        
        # 更新用户信息
        user.username = username
        user.email = email
        
        # 处理密码更新
        current_password = request.form['current_password']
        new_password = request.form['new_password']
        confirm_new_password = request.form['confirm_new_password']
        
        if current_password or new_password or confirm_new_password:
            # 如果填写了任何密码字段，则需要验证所有密码字段
            if not current_password or not new_password or not confirm_new_password:
                flash('更新密码时，请填写所有密码字段', 'danger')
                return redirect(url_for('settings'))
            
            # 验证当前密码
            if not user.check_password(current_password):
                flash('当前密码不正确', 'danger')
                return redirect(url_for('settings'))
            
            # 验证新密码和确认密码
            if new_password != confirm_new_password:
                flash('两次输入的新密码不一致', 'danger')
                return redirect(url_for('settings'))
            
            # 更新密码
            user.set_password(new_password)
        
        try:
            db.session.commit()
            # 更新session中的用户名
            session['username'] = user.username
            flash('设置已更新', 'success')
            return redirect(url_for('settings'))
        except:
            db.session.rollback()
            flash('设置更新失败，请稍后再试', 'danger')
            return redirect(url_for('settings'))
    
    return render_template('settings.html', user=user)

# 通知中心
@app.route('/notifications')
@login_required
def notifications():
    user_id = session['user_id']
    notifications = Notification.query.filter_by(user_id=user_id).order_by(Notification.created_at.desc()).all()
    
    # 标记所有通知为已读
    for notification in notifications:
        if not notification.is_read:
            notification.is_read = True
    db.session.commit()
    
    return render_template('notifications.html', notifications=notifications)

# 数据统计和报表
@app.route('/reports')
@login_required
def reports():
    user_id = session['user_id']
    
    # 按状态统计任务数量
    status_counts = {
        'todo': Task.query.filter_by(user_id=user_id, status='todo').count(),
        'in_progress': Task.query.filter_by(user_id=user_id, status='in_progress').count(),
        'completed': Task.query.filter_by(user_id=user_id, status='completed').count(),
        'archived': Task.query.filter_by(user_id=user_id, status='archived').count()
    }
    
    # 按优先级统计任务数量
    priority_counts = {
        'high': Task.query.filter_by(user_id=user_id, priority='high').count(),
        'medium': Task.query.filter_by(user_id=user_id, priority='medium').count(),
        'low': Task.query.filter_by(user_id=user_id, priority='low').count()
    }
    
    # 按分类统计任务数量
    categories = Category.query.filter_by(user_id=user_id).all()
    category_counts = {}
    category_colors = {}
    for cat in categories:
        count = Task.query.filter_by(user_id=user_id, category_id=cat.id).count()
        if count > 0:
            category_counts[cat.name] = count
            category_colors[cat.name] = cat.color
    
    # 获取本月完成的任务数
    this_month = datetime.utcnow().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
    completed_this_month = Task.query.filter(
        Task.user_id == user_id,
        Task.status == 'completed',
        Task.updated_at >= this_month
    ).count()
    
    # 获取上月完成的任务数
    last_month = (this_month - timedelta(days=1)).replace(day=1)
    completed_last_month = Task.query.filter(
        Task.user_id == user_id,
        Task.status == 'completed',
        Task.updated_at >= last_month,
        Task.updated_at < this_month
    ).count()
    
    # 计算环比增长
    growth_rate = 0
    if completed_last_month > 0:
        growth_rate = ((completed_this_month - completed_last_month) / completed_last_month) * 100
    elif completed_this_month > 0:
        growth_rate = 100
    
    # 获取最近7天的任务完成情况
    daily_completed = []
    for i in range(6, -1, -1):
        date = datetime.utcnow().date() - timedelta(days=i)
        start_date = datetime.combine(date, datetime.min.time())
        end_date = datetime.combine(date, datetime.max.time())
        count = Task.query.filter(
            Task.user_id == user_id,
            Task.status == 'completed',
            Task.updated_at >= start_date,
            Task.updated_at <= end_date
        ).count()
        daily_completed.append({
            'date': date.strftime('%m-%d'),
            'count': count
        })
    
    return render_template('reports.html',
                           status_counts=status_counts,
                           priority_counts=priority_counts,
                           category_counts=category_counts,
                           category_colors=category_colors,
                           completed_this_month=completed_this_month,
                           completed_last_month=completed_last_month,
                           growth_rate=growth_rate,
                           daily_completed=daily_completed)

# 主程序入口
if __name__ == '__main__':
    with app.app_context():
        init_db()
    app.run(debug=True)